package com.upb.webserver.fisco.application;

import cn.hutool.core.collection.CollectionUtil;
import com.upb.webserver.application.ApplicationService;
import com.upb.webserver.applicationorg.ApplicationOrgService;
import com.upb.webserver.common.enums.ChainOrAppStatusEnum;
import com.upb.webserver.common.enums.OrgTypeEnum;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.pojo.order.ReqAddWorkOrderOfNewApplicationVO;
import com.upb.webserver.common.pojo.rest.fisco.chainmgr.resp.RespGroup;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.company.CompanyDeveloperService;
import com.upb.webserver.dao.entity.TbApplication;
import com.upb.webserver.dao.mapper.TbApplicationMapper;
import com.upb.webserver.developerappmap.DeveloperAppMapService;
import com.upb.webserver.rest.fisco.FiscoChainMgrRestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FiscoApplicationService {

    @Autowired
    private TbApplicationMapper tbApplicationMapper;
    @Autowired
    private ApplicationOrgService applicationOrgService;
    @Autowired
    private CompanyDeveloperService companyDeveloperService;
    @Autowired
    private ApplicationService applicationService;
    @Autowired
    private FiscoChainMgrRestService fiscoChainMgrRestService;
    @Autowired
    private DeveloperAppMapService developerAppMapService;

    /**
     * @param newApplicationVO
     */
    @Transactional
    public int createFiscoApplication(Byte platform, int creatorId, ReqAddWorkOrderOfNewApplicationVO newApplicationVO) {
        log.warn("start exec method [createFiscoApplication]. platform:{} creatorId:{} newApplicationVO:{}", platform, creatorId, JsonUtils.objToString(newApplicationVO));

        //save application
        TbApplication tbApplication = applicationService.saveNewApplication(platform, creatorId, newApplicationVO);

        //add developer-app map
        Set<Integer> companyIdSet = newApplicationVO.getConfirmOrgList().stream().map(co -> co.getCompanyId()).collect(Collectors.toSet());
        developerAppMapService.addByApplicationSetAndCompanySet(CollectionUtil.newHashSet(tbApplication.getId()), companyIdSet);


        // rest to generate group
        List<Integer> orgIdList = newApplicationVO.getConfirmOrgList().stream().map(o -> o.getOrgId()).collect(Collectors.toList());
        orgIdList.stream().forEach(o -> applicationOrgService.saveApplicationOrg(newApplicationVO.getChainId(), tbApplication.getId(), o, OrgTypeEnum.FISCO_ORG.getValue()));

        //deploy
        RespGroup rspGroup = null;
        tbApplication.setGmtModified(new Date());
        tbApplication.setCreateStatus(ChainOrAppStatusEnum.DEPLOY_FAIL.getId());
        try {
            rspGroup = fiscoChainMgrRestService.createFiscoGroup(
                    newApplicationVO.getChainId(), tbApplication.getId(), orgIdList, tbApplication.getFinalName(), newApplicationVO.getDescription());
            String rspJson = Objects.nonNull(rspGroup) ? JsonUtils.objToString(rspGroup) : "null";
            log.info("deployRspJson:{}", rspJson);
        } catch (WebServerException ex) {
            log.error("WebServerException.fail exec deploy channel to remote server", ex);
            throw ex;
//            tbApplication.setRemark(ex.getRetCode().getMessage());
//            tbApplicationMapper.updateByPrimaryKey(tbApplication);
//            throw OperationException.fromWebServerException(ex);
        } catch (Exception ex) {
            log.error("Exception.fail exec deploy channel to remote server", ex);
//            tbApplication.setRemark(ex.getMessage());
//            tbApplicationMapper.updateByPrimaryKey(tbApplication);
            throw new WebServerException(ConstantCode.APPLICATION_DEPLOY_FAIL.msg(ex.getMessage()));
        }

        //update application
        if (Objects.isNull(rspGroup)) {
            log.error("Exception.fail exec deploy channel to remote server, rspGroup is null");
//            tbApplication.setRemark("rspGroup is null");
//            tbApplicationMapper.updateByPrimaryKey(tbApplication);
            throw new WebServerException(ConstantCode.APPLICATION_DEPLOY_FAIL.msg("remote server result is null"));
        }

        log.info("success exec method [createFiscoApplication]. [{}:{}:{}]", rspGroup.getChainId(), rspGroup.getGroupId(), rspGroup.getGroupStatus());
        tbApplication.setCreateStatus(ChainOrAppStatusEnum.RUNNING.getId());
        tbApplication.setRemoteId(tbApplication.getId());
        tbApplicationMapper.updateByPrimaryKey(tbApplication);

        log.info("finish exec method [createFiscoApplication]. newApplicationVO:{}", JsonUtils.objToString(newApplicationVO));
        return tbApplication.getId();
    }
}
